package com.ssy.lingxi.order.serviceimpl.feign;

import com.ssy.lingxi.common.model.dto.MemberAndRoleIdDTO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.logistics.api.dto.request.*;
import com.ssy.lingxi.logistics.api.dto.response.FreightResponse;
import com.ssy.lingxi.logistics.api.dto.response.OrderSeparateFreightListResponse;
import com.ssy.lingxi.logistics.api.dto.response.ShipperAddressDetailResponse;
import com.ssy.lingxi.logistics.api.feign.FreightRemoteControllerFeign;
import com.ssy.lingxi.logistics.api.feign.ShipperAddressControllerFeign;
import com.ssy.lingxi.order.api.model.vo.response.OrderFreeExpressConfigVO;
import com.ssy.lingxi.order.model.bo.LogisticsProductBO;
import com.ssy.lingxi.order.model.bo.LogisticsProductDetailBO;
import com.ssy.lingxi.order.model.dto.OrderConsigneeDTO;
import com.ssy.lingxi.order.model.dto.OrderSeparateDTO;
import com.ssy.lingxi.order.model.dto.ProductAddressDTO;
import com.ssy.lingxi.order.model.vo.basic.request.OrderProductFreeFreightVO;
import com.ssy.lingxi.order.model.vo.basic.request.ProductFreeFreightVO;
import com.ssy.lingxi.order.service.feign.ILogisticsFeignService;
import com.ssy.lingxi.order.service.web.IOrderParamConfigService;
import com.ssy.lingxi.order.utils.NumberUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 物流服务Feign接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-09-14
 */
@Service
public class LogisticsFeignServiceImpl implements ILogisticsFeignService {

    @Resource
    private ShipperAddressControllerFeign shipperAddressFeign;
    @Resource
    private FreightRemoteControllerFeign freightRemoteControllerFeign;
    @Resource
    private IOrderParamConfigService orderParamConfigService;


    /**
     * 查询配送方式为“自提”的商品地址
     *
     * @param addressIds 地址Id列表
     * @return 查询结果
     */
    @Override
    public Wrapper<List<ProductAddressDTO>> findProductAddresses(List<Long> addressIds) {
        if(CollectionUtils.isEmpty(addressIds)) {
            return Wrapper.success(new ArrayList<>());
        }

        CommonIdsRequest request = new CommonIdsRequest();
        request.setIds(addressIds);
        try {
            Wrapper<List<ShipperAddressDetailResponse>> addressResult = shipperAddressFeign.listShipperAddress(request);
            if (addressResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(addressResult.getCode(), addressResult.getMessage());
            }

            return Wrapper.success(addressResult.getData().stream().map(r -> {
                ProductAddressDTO productAddress = new ProductAddressDTO();
                productAddress.setAddressId(r.getId());
                productAddress.setProvinceCode(r.getProvinceCode());
                productAddress.setProvinceName(r.getProvinceName());
                productAddress.setCityCode(r.getCityCode());
                productAddress.setCityName(r.getCityName());
                productAddress.setDistrictCode(r.getDistrictCode());
                productAddress.setDistrictName(r.getDistrictName());
                productAddress.setStreetCode(r.getStreetCode());
                productAddress.setStreetName(r.getStreetName());
                productAddress.setAddress(r.getAddress());
                productAddress.setReceiver(r.getShipperName());
                productAddress.setPhone(r.getPhone());
                productAddress.setFullAddress(r.getFullAddress());
                return productAddress;
            }).collect(Collectors.toList()));
        } catch (Exception ignored) {
            return Wrapper.fail(ResponseCode.SERVICE_LOGISTICS_ERROR);
        }
    }

    /**
     * 生成供应商收货人信息，计算转单订单的运费
     *
     * @param logisticsProducts 订单、供应商、上游供应商商品信息
     * @return 查询结果
     */
    @Override
    public Wrapper<List<OrderConsigneeDTO>> findVendorConsignee(List<LogisticsProductBO> logisticsProducts) {
        List<TransferOrderFreightRequest> requests = logisticsProducts.stream().map(logisticsProduct -> {
            TransferOrderFreightRequest request = new TransferOrderFreightRequest();
            request.setOrderId(logisticsProduct.getOrderId());
            request.setMemberId(logisticsProduct.getVendorMemberId());
            request.setRoleId(logisticsProduct.getVendorRoleId());
            request.setReceiverAddressId(logisticsProduct.getConsigneeId());
            request.setProductFreightDetailList(logisticsProduct.getSupplyProducts().stream().map(product -> {
                ProductFreightDetail detail = new ProductFreightDetail();
                detail.setTemplateId(product.getTemplateId());
                detail.setWeight(product.getWeight().doubleValue());
                detail.setCount(product.getQuantity().doubleValue());
                return detail;
            }).collect(Collectors.toList()));
            return request;
        }).collect(Collectors.toList());

        Wrapper<List<FreightResponse>> logisticsResult = freightRemoteControllerFeign.batchCalFreightPrice(requests);
        if(logisticsResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(logisticsResult.getCode(), logisticsResult.getMessage());
        }

        return Wrapper.success(CollectionUtils.isEmpty(logisticsResult.getData()) ? new ArrayList<>() : logisticsResult.getData().stream().map(r -> {
            OrderConsigneeDTO consigneeDTO = new OrderConsigneeDTO();
            consigneeDTO.setOrderId(r.getOrderId());
            consigneeDTO.setConsigneeId(r.getReceiverAddressId());
            consigneeDTO.setConsignee(r.getReceiverName());
            consigneeDTO.setProvinceCode(r.getProvinceCode());
            consigneeDTO.setProvinceName(r.getProvinceName());
            consigneeDTO.setCityCode(r.getCityCode());
            consigneeDTO.setCityName(r.getCityName());
            consigneeDTO.setDistrictCode(r.getDistrictCode());
            consigneeDTO.setDistrictName(r.getDistrictName());
            consigneeDTO.setAddress(StringUtils.hasLength(r.getAddress()) ? r.getAddress() : "");
            consigneeDTO.setPostalCode(StringUtils.hasLength(r.getPostalCode()) ? r.getPostalCode() : "");
            consigneeDTO.setCountryCode(StringUtils.hasLength(r.getAreaCode()) ? r.getAreaCode() : "");
            consigneeDTO.setPhone(StringUtils.hasLength(r.getPhone()) ? r.getPhone() : "");
            consigneeDTO.setTelephone(StringUtils.hasLength(r.getTel()) ? r.getTel() : "");
            consigneeDTO.setDefaultConsignee(!NumberUtil.isNullOrZero(r.getIsDefault()) && (r.getIsDefault().compareTo(1) == 0));
            consigneeDTO.setFreight(NumberUtil.isNullOrZero(r.getFreightPrice()) ? BigDecimal.ZERO : r.getFreightPrice());
            return consigneeDTO;
        }).collect(Collectors.toList()));
    }

    /**
     * （拆单）查询商品的运费
     *
     * @param consigneeId 收货人地址Id
     * @param products 拆单后的商品列表
     * @return 查询结果
     */
    @Override
    public Wrapper<Map<OrderSeparateDTO, BigDecimal>> findSeparateOrderFreight(Long consigneeId, Map<OrderSeparateDTO,  List<LogisticsProductDetailBO>> products) {
        List<OrderSeparateFreightListRequest> requests = products.entrySet().stream().map(entry -> {
            OrderSeparateFreightListRequest request = new OrderSeparateFreightListRequest();
            request.setRequest(new OrderSeparateFreightRequest(entry.getKey().getVendorMemberId(), entry.getKey().getVendorRoleId(), entry.getKey().getSupplyMemberId(), entry.getKey().getSupplyRoleId()));
            request.setProducts(entry.getValue().stream().filter(productVO -> NumberUtil.notNullAndPositive(productVO.getTemplateId()) && NumberUtil.notNullAndPositive(productVO.getWeight()) && NumberUtil.notNullAndPositive(productVO.getQuantity())).map(product -> {
                OrderSeparateProductFreightDetail detail = new OrderSeparateProductFreightDetail();
                detail.setReceiverAddressId(consigneeId);
                detail.setTemplateId(product.getTemplateId());
                detail.setWeight(product.getWeight().doubleValue());
                detail.setCount(product.getQuantity().doubleValue());
                return detail;
            }).collect(Collectors.toList()));
            return request;
        }).collect(Collectors.toList());

        requests.removeIf(r -> CollectionUtils.isEmpty(r.getProducts()));

        if(CollectionUtils.isEmpty(requests)) {
            return Wrapper.success(products.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, p -> BigDecimal.ZERO)));
        }

        Wrapper<List<OrderSeparateFreightListResponse>> freightResult = freightRemoteControllerFeign.findSeparateOrderFreight(requests);
        if(freightResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(freightResult.getCode(), freightResult.getMessage());
        }

        return Wrapper.success(products.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, p ->
            freightResult.getData().stream().filter(r -> r.getRequest().equals(new OrderSeparateFreightRequest(p.getKey().getVendorMemberId(), p.getKey().getVendorRoleId(), p.getKey().getSupplyMemberId(), p.getKey().getSupplyRoleId()))).map(OrderSeparateFreightListResponse::getFreight).findFirst().orElse(BigDecimal.ZERO)
        )));
    }

    /**
     * 查询订单运费
     *
     * @param consigneeId       收货人地址Id
     * @param logisticsProducts 订单商品信息列表
     * @return 订单运费
     */
    @Override
    public Wrapper<BigDecimal> findOrderFreight(Long consigneeId, List<LogisticsProductDetailBO> logisticsProducts) {
        if(CollectionUtils.isEmpty(logisticsProducts)) {
            return Wrapper.success(BigDecimal.ZERO);
        }

        OrderFreightRequest request = new OrderFreightRequest();
        request.setReceiverAddressId(consigneeId);
        request.setProductFreightDetailList(logisticsProducts.stream().map(product -> {
            ProductFreightDetail detail = new ProductFreightDetail();
            detail.setTemplateId(product.getTemplateId());
            detail.setCount(product.getQuantity().doubleValue());
            detail.setWeight(product.getWeight().doubleValue());
            return detail;
        }).collect(Collectors.toList()));

        return freightRemoteControllerFeign.calFreightPrice(request);
    }

    /**
     * 查询满额包邮的商品总运费
     * @param freightVO 接口参数
     * @return 订单运费
     */
    @Override
    public Wrapper<BigDecimal> findOrderFreeFreight(OrderProductFreeFreightVO freightVO) {
        List<ProductFreeFreightVO> logisticsProducts = freightVO.getProductFreightDetailList();
        if (CollectionUtils.isEmpty(logisticsProducts)) {
            return Wrapper.success(BigDecimal.ZERO);
        }

        List<MemberAndRoleIdDTO> memberList = logisticsProducts
                .stream().map(p -> {
                    MemberAndRoleIdDTO member = new MemberAndRoleIdDTO();
                    member.setMemberId(p.getMemberId());
                    member.setRoleId(p.getRoleId());
                    return member;
                }).collect(Collectors.toList());
        List<OrderFreeExpressConfigVO> freeExpressConfigList = orderParamConfigService.getOrderFreeExpressConfigList(memberList);

        Map<Long, BigDecimal> totalAmountMap = logisticsProducts.stream().collect(Collectors.toMap(ProductFreeFreightVO::getMemberId, p -> p.getRefPrice().multiply(p.getCount()), BigDecimal::add));


        List<ProductFreeFreightVO> freightProductList = new ArrayList<>(logisticsProducts);
        for (OrderFreeExpressConfigVO configVO : freeExpressConfigList) {
            BigDecimal totalAmount = totalAmountMap.getOrDefault(configVO.getMemberId(), BigDecimal.ZERO);
            if (totalAmount.compareTo(configVO.getOrderAmount()) >= 0) {
                freightProductList.removeIf(p -> p.getMemberId().equals(configVO.getMemberId()) && p.getRoleId().equals(configVO.getRoleId()));
            }
        }

        OrderFreightRequest request = new OrderFreightRequest();
        request.setReceiverAddressId(freightVO.getReceiverAddressId());
        request.setProductFreightDetailList(freightProductList.stream().map(product -> {
            ProductFreightDetail detail = new ProductFreightDetail();
            detail.setTemplateId(product.getTemplateId());
            detail.setCount(product.getCount().doubleValue());
            detail.setWeight(product.getWeight().doubleValue());
            return detail;
        }).collect(Collectors.toList()));

        return freightRemoteControllerFeign.calFreightPrice(request);
    }
}
